home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / srcuc.zip / CMPINT-I.H < prev    next >
C/C++ Source or Header  |  1992-05-04  |  26KB  |  771 lines

  1. /* -*-C-*-
  2.  
  3. $Header: /scheme/src/microcode/RCS/cmpint-i386.h,v 1.17 1992/05/04 18:31:13 jinx Exp $
  4.  
  5. Copyright (c) 1992 Massachusetts Institute of Technology
  6.  
  7. This material was developed by the Scheme project at the Massachusetts
  8. Institute of Technology, Department of Electrical Engineering and
  9. Computer Science.  Permission to copy this software, to redistribute
  10. it, and to use it for any purpose is granted, subject to the following
  11. restrictions and understandings.
  12.  
  13. 1. Any copy made of this software must include this copyright notice
  14. in full.
  15.  
  16. 2. Users of this software agree to make their best efforts (a) to
  17. return to the MIT Scheme project any improvements or extensions that
  18. they make, so that these may be included in future releases; and (b)
  19. to inform MIT of noteworthy uses of this software.
  20.  
  21. 3. All materials developed as a consequence of the use of this
  22. software shall duly acknowledge such use, in accordance with the usual
  23. standards of acknowledging credit in academic research.
  24.  
  25. 4. MIT has made no warrantee or representation that the operation of
  26. this software will be error-free, and MIT is under no obligation to
  27. provide any services, by way of maintenance, update, or otherwise.
  28.  
  29. 5. In conjunction with products arising from the use of this material,
  30. there shall be no use of the name of the Massachusetts Institute of
  31. Technology nor of any adaptation thereof in any advertising,
  32. promotional, or sales literature without prior written consent from
  33. MIT in each case. */
  34.  
  35. /*
  36.  *
  37.  * Compiled code interface macros.
  38.  *
  39.  * See cmpint.txt for a description of these fields.
  40.  *
  41.  * Specialized for the Intel 386 (and successors) architecture.
  42.  */
  43.  
  44. #ifndef CMPINT2_H_INCLUDED
  45. #define CMPINT2_H_INCLUDED
  46.  
  47. #define COMPILER_NONE_TYPE            0
  48. #define COMPILER_MC68020_TYPE            1
  49. #define COMPILER_VAX_TYPE            2
  50. #define COMPILER_SPECTRUM_TYPE            3
  51. #define COMPILER_MIPS_TYPE            4
  52. #define COMPILER_MC68040_TYPE            5
  53. #define COMPILER_SPARC_TYPE            6
  54. #define COMPILER_RS6000_TYPE            7
  55. #define COMPILER_MC88K_TYPE            8
  56. #define COMPILER_I386_TYPE            9
  57. #define COMPILER_ALPHA_TYPE            10
  58.  
  59. /*
  60.  
  61.     Problems with i386 ISA (instruction set architecture)
  62.  
  63. <1> Code space is separate from data space.  The only way to obtain a
  64. code space address is to do a CALL and use the return address on the
  65. stack.
  66.  
  67. Problem: References to the constants vector in compiled code.
  68.  
  69. Fix: Just as on RISC machines.  Use CALL when necessary, and cache the
  70. result in the assembly language.
  71.  
  72.  
  73. <2> Jumps are PC-relative.  There are absolute jumps, assuming the PC
  74. is in a data location, or with immediate destinations that include a
  75. segment descriptor (16 bits).  The short forms have a PC-relative
  76. offset defined with respect to the immediately following instruction.
  77.  
  78. Problem: Closures and execute caches need their address in old space
  79. in order to be relocated correctly.
  80.  
  81. Fix: 
  82.  
  83.   For execute caches we can define a new linker field, called
  84. load-relocation-address which on every GC/relocation stores the new
  85. address and the old contents into global variables and stores the new
  86. address in the field.  Alternatively the difference between the new
  87. address and the old contents can be stored into a single global
  88. variable, and this can be used, together with the new address of each
  89. cache, to find the old code.
  90.  
  91.   For closures the code that reads the header (manifest closure) can
  92. do the same.
  93.  
  94.  
  95. <3> The stack pointer register (ESP) cannot be used as the base in
  96. (base + displacement) addressing mode.
  97.  
  98. Problem: Common operation in the compiler, which assumes direct access
  99. to the stack.
  100.  
  101. Fix: Use base + indexed mode, which allows specification of ESP as
  102. base and nullification of the index (by using ESP again).
  103. This is one byte longer than otherwise, but...
  104.  
  105.     Register assignments
  106.  
  107. EAX (0)        Unassigned
  108. ECX (1)        Unassigned
  109. EDX (2)        Unassigned
  110. EBX (3)        Unassigned
  111.  
  112. ESP (4)        Stack Pointer
  113. EBP (5)        Register Mask
  114. ESI (6)        Pointer to register block, etc.
  115. EDI (7)        Free Pointer
  116.  
  117. The dynamic link and value "registers" are not processor registers.
  118. Slots in the register array must be reserved for them.
  119.  
  120. The Free Pointer is EDI because EDI is the implicit base register for
  121. the memory-to-memory move instructions, and the string store
  122. instruction.  Perhaps we can make use of it.
  123.  
  124. The pointer to register block is not held in EBP (the processor's
  125. "frame" register is typically used) because its most common use, (EBP)
  126. (address syllable for memory memtop) takes more bytes than (ESI).
  127.  
  128.     Encodings and layout of various control features:
  129.  
  130. Assumptions:
  131.  
  132.   The processor will be in 32-bit address and operand mode.
  133. Thus instructions use 32-bit operands, and displacements for
  134. addressing modes and jump instructions are all 32-bits by default.
  135.  
  136.     Offset        Contents        Encoding
  137.  
  138.  
  139. - Execute cache entry encoding:
  140.  
  141.         Before linking
  142.  
  143.     0        16-bit arity    \
  144.     2        0x00          [TC_FIXNUM | arity]
  145. entry    3        0x1A        /
  146.     4        Symbol
  147.     8        <next cache>
  148.  
  149.         After linking
  150.  
  151.     0        16-bit arity
  152.     2        0x00
  153. entry    3        JMP opcode        0x39
  154.     4        32-bit offset
  155.     8        <next cache>
  156.  
  157. Arity stays in place because the i386 is a little-endian architecture.
  158.  
  159.  
  160. - Closure entry encoding:
  161.  
  162. entry    0        CALL opcode        0xE8
  163.     1        32-bit offset
  164.     5        <padding>        0x00
  165.     6        <next entry or variables>
  166.  
  167.  
  168. - Trampoline encoding:
  169.  
  170. entry    0        MOV    AL,code        0xB0, code-byte
  171.     2        CALL    n(ESI)        0xFF 0x96 n-longword
  172.     8        <trampoline dependent storage>
  173.  
  174.  
  175. - GC & interrupt check at procedure/continuation entry:
  176.  
  177. gc_lab    -7        CALL    n(ESI)        0xFF 0x56 n-byte
  178.     -4        <type/arity info>
  179.     -2        <gc offset>
  180. entry    0        CMP    EDI,(ESI)    0x39 0x3e
  181.     2        JAE    gc_lab        0x73 -11
  182.     4        <real code>
  183.  
  184.  
  185. - GC & interrupt check at closure entry:
  186.  
  187. gc_lab    -11        ADD    (ESP),&offset    0x83 0x04 0x24 offset-byte
  188.       -7        JMP    n(ESI)        0xFF 0x66 n-byte
  189.     -4        <type/arity info>
  190.     -2        <gc offset>
  191. entry    0        ADD    (ESP),&magic    0x81 0x04 0x24 magic-longword
  192.     7        CMP    EDI,(ESI)    0x39 0x3e
  193.     9        JAE    gc_lab        0x73 0xea (= -22)
  194.     11        <real code>
  195.  
  196. The magic value depends on the closure because of canonicalization.
  197.  
  198. The ADD instruction at offset -11 is not present for the 0th closure
  199. entry, since it is the canonical entry point.  Its format depends on
  200. the value of offset, since the sign-extending forms often suffice.
  201.  
  202. offset = entry_number * entry_size
  203. magic = ([TC_COMPILED_ENTRY | 0] - (offset + length_of_CALL_instruction))
  204.  
  205. */
  206.  
  207. #define COMPILER_PROCESSOR_TYPE            COMPILER_I386_TYPE
  208.  
  209. /* The i387 coprocessor and i486 use 80-bit extended format internally. */
  210.  
  211. #define COMPILER_TEMP_SIZE            3
  212.  
  213. typedef unsigned short format_word;
  214.  
  215. /* i386 instructions can be aligned on any byte boundary. */
  216.  
  217. #define PC_ZERO_BITS                        0
  218.  
  219. /* See the encodings above. */
  220.  
  221. #define ENTRY_SKIPPED_CHECK_OFFSET         4
  222. #define ENTRY_PREFIX_LENGTH            3
  223.  
  224. #define CLOSURE_SKIPPED_CHECK_OFFSET         11
  225.  
  226. #  define COMPILED_CLOSURE_ENTRY_SIZE                    \
  227.   ((2 * (sizeof (format_word))) + 6)
  228.  
  229. #  define ADJUST_CLOSURE_AT_CALL(entry_point, location)            \
  230. do {                                    \
  231.   long magic_constant;                            \
  232.                                     \
  233.   magic_constant = (* ((long *) (((char *) (entry_point)) + 3)));    \
  234.   (location) = ((SCHEME_OBJECT)                        \
  235.         ((((long) (OBJECT_ADDRESS (location))) + 5) +        \
  236.          magic_constant));                    \
  237. } while (0)
  238.  
  239. /* For the relocation of PC-relative JMP and CALL instructions.
  240.    This is used during GC/relocation, when the displacement
  241.    is incorrect, since it was computed with respect to the
  242.    location in old space.
  243.  */
  244.  
  245. extern long i386_pc_displacement_relocation;
  246.  
  247. #define EXTRACT_ADDRESS_FROM_DISPLACEMENT(var, instr_addr) do        \
  248. {                                    \
  249.   long displacement_address, new_displacement;                \
  250.                                     \
  251.   displacement_address = (((long) (instr_addr)) + 1);            \
  252.   new_displacement = ((* ((long *) displacement_address))        \
  253.               + i386_pc_displacement_relocation);        \
  254.   (* ((long *) displacement_address)) = new_displacement;        \
  255.   (var) = ((SCHEME_OBJECT)                        \
  256.        ((displacement_address + 4) + new_displacement));        \
  257. } while (0)
  258.  
  259. #define STORE_DISPLACEMENT_FROM_ADDRESS(target, instr_address) do    \
  260. {                                    \
  261.   long displacement_address = (((long) (instr_address)) + 1);        \
  262.   (* ((long *) displacement_address)) =                    \
  263.     (((long) (target)) - (displacement_address + 4));            \
  264. } while (0)
  265.  
  266. #define BCH_EXTRACT_ADDRESS_FROM_DISPLACEMENT(var, v_addr, p_addr) do    \
  267. {                                    \
  268.   long displacement_address, new_displacement;                \
  269.                                     \
  270.   displacement_address = (((long) (p_addr)) + 1);            \
  271.   new_displacement = ((* ((long *) displacement_address))        \
  272.               + i386_pc_displacement_relocation);        \
  273.   (* ((long *) displacement_address)) = new_displacement;        \
  274.   (var) = ((SCHEME_OBJECT)                        \
  275.        ((((long) (v_addr)) + 5) + new_displacement));        \
  276. } while (0)
  277.  
  278. #define BCH_STORE_DISPLACEMENT_FROM_ADDRESS(target, v_addr, p_addr) do    \
  279. {                                    \
  280.   long displacement_address = (((long) (p_addr)) + 1);            \
  281.   (* ((long *) displacement_address))                    \
  282.     = (((long) (target)) - (((long) (v_addr)) + 5));            \
  283. } while (0)
  284.  
  285. #define START_CLOSURE_RELOCATION(scan) do                \
  286. {                                    \
  287.   SCHEME_OBJECT * _block, * _old;                    \
  288.   char * _new;                                \
  289.                                     \
  290.   _block = ((SCHEME_OBJECT *) (scan));                    \
  291.   _old = (OBJECT_ADDRESS (_block[(OBJECT_DATUM (*_block))]));        \
  292.   _new = ((char *) (FIRST_MANIFEST_CLOSURE_ENTRY (_block + 1)));    \
  293.                                     \
  294.   i386_pc_displacement_relocation = (((long) _old) - ((long) _new));    \
  295. } while (0)
  296.  
  297. #define END_CLOSURE_RELOCATION(scan)    i386_pc_displacement_relocation = 0
  298. #define EXTRACT_CLOSURE_ENTRY_ADDRESS    EXTRACT_ADDRESS_FROM_DISPLACEMENT
  299. #define STORE_CLOSURE_ENTRY_ADDRESS    STORE_DISPLACEMENT_FROM_ADDRESS
  300.  
  301. #define BCH_START_CLOSURE_RELOCATION(scan) do                \
  302. {                                    \
  303.   SCHEME_OBJECT * _scan, * _block, _old_obj, * _old;            \
  304.   char * _new;                                \
  305.                                     \
  306.   _scan = ((SCHEME_OBJECT *) (scan));                    \
  307.   _block = ((SCHEME_OBJECT *)                        \
  308.         (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_scan)));        \
  309.   READ_NEWSPACE_ADDRESS (_old_obj,                    \
  310.              (_block + (OBJECT_DATUM (* _scan))));        \
  311.   _old = (OBJECT_ADDRESS (_old_obj));                    \
  312.   _new = ((char *) (FIRST_MANIFEST_CLOSURE_ENTRY (_scan + 1)));        \
  313.                                     \
  314.   i386_pc_displacement_relocation                    \
  315.     = (((long) _old)                            \
  316.        - ((long) (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_new))));        \
  317. } while (0)
  318.  
  319. #define BCH_END_CLOSURE_RELOCATION    END_CLOSURE_RELOCATION
  320.  
  321. #define BCH_EXTRACT_CLOSURE_ENTRY_ADDRESS(var, p_addr) do        \
  322. {                                    \
  323.   SCHEME_OBJECT * _p_addr, * _v_addr;                    \
  324.                                     \
  325.   _p_addr = ((SCHEME_OBJECT *) (p_addr));                \
  326.   _v_addr = ((SCHEME_OBJECT *)                        \
  327.          (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));        \
  328.                                     \
  329.   BCH_EXTRACT_ADDRESS_FROM_DISPLACEMENT (var, _v_addr, _p_addr);    \
  330. } while (0)
  331.  
  332. #define BCH_STORE_CLOSURE_ENTRY_ADDRESS(target, p_addr) do        \
  333. {                                    \
  334.   SCHEME_OBJECT * _p_addr, * _v_addr;                    \
  335.                                     \
  336.   _p_addr = ((SCHEME_OBJECT *) (p_addr));                \
  337.   _v_addr = ((SCHEME_OBJECT *)                        \
  338.          (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));        \
  339.                                     \
  340.   BCH_STORE_DISPLACEMENT_FROM_ADDRESS (target, _v_addr, _p_addr);    \
  341. } while (0)
  342.  
  343. #define EXECUTE_CACHE_ENTRY_SIZE        2
  344.  
  345. #define FIRST_OPERATOR_LINKAGE_OFFSET        2
  346.  
  347. #define EXTRACT_EXECUTE_CACHE_ARITY(target, address) do            \
  348. {                                    \
  349.   (target) = ((long) (* ((unsigned short *) (address))));        \
  350. } while (0)
  351.  
  352. #define EXTRACT_EXECUTE_CACHE_SYMBOL(target, address) do        \
  353. {                                    \
  354.   (target) = (* (((SCHEME_OBJECT *) (address)) + 1));            \
  355. } while (0)
  356.  
  357. /* This is used during GC/relocation.
  358.    The displacement stored in the instruction refers to the old space
  359.    location.
  360.  */   
  361.  
  362. #define EXTRACT_OPERATOR_LINKAGE_ADDRESS(target, address) do        \
  363. {                                    \
  364.   EXTRACT_ADDRESS_FROM_DISPLACEMENT (target,                \
  365.                      (((long) (address)) + 3));        \
  366. } while (0)
  367.  
  368. /* This is used when not relocating.
  369.    The displacement refers to the current location of the instruction.
  370.  */
  371.  
  372. #define EXTRACT_EXECUTE_CACHE_ADDRESS(loc, cache_addr) do        \
  373. {                                    \
  374.   long displacement_address, displacement;                \
  375.                                     \
  376.   displacement_address = (((long) (cache_addr)) + 4);            \
  377.   displacement = (* ((long *) displacement_address));            \
  378.   (loc) = ((SCHEME_OBJECT)                        \
  379.        ((displacement_address + 4) + displacement));        \
  380. } while (0)
  381.  
  382. #define STORE_EXECUTE_CACHE_ADDRESS(address, entry_address) do        \
  383. {                                    \
  384.   STORE_DISPLACEMENT_FROM_ADDRESS (entry_address,            \
  385.                    (((long) (address)) + 3));        \
  386. } while (0)
  387.  
  388. #define STORE_EXECUTE_CACHE_CODE(address) do                \
  389. {                                    \
  390.   /* Store a <JMP rel32> opcode. */                    \
  391.   (* (((unsigned char *) (address)) + 3)) = 0xe9;            \
  392. } while (0)
  393.  
  394. #define START_OPERATOR_RELOCATION(scan)    do                \
  395. {                                    \
  396.   SCHEME_OBJECT * _new, * _old;                        \
  397.                                     \
  398.   _new = (((SCHEME_OBJECT *) (scan)) + 1);                \
  399.   _old = ((SCHEME_OBJECT *) (* _new));                    \
  400.                                     \
  401.   (* _new) = ((SCHEME_OBJECT) _new);                    \
  402.   i386_pc_displacement_relocation = (((long) _old) - ((long) _new));    \
  403. } while (0)
  404.  
  405. #define END_OPERATOR_RELOCATION(scan)    i386_pc_displacement_relocation = 0
  406.  
  407. #define BCH_START_OPERATOR_RELOCATION(scan) do                \
  408. {                                    \
  409.   SCHEME_OBJECT * _scan, * _new, * _old;                \
  410.                                     \
  411.   _scan = (((SCHEME_OBJECT *) (scan)) + 1);                \
  412.   _new = ((SCHEME_OBJECT *)                        \
  413.       (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_scan)));            \
  414.   _old = ((SCHEME_OBJECT *) (* _scan));                    \
  415.                                     \
  416.   * _scan = ((SCHEME_OBJECT) _new);                    \
  417.   i386_pc_displacement_relocation = (((long) _old) - ((long) _new));    \
  418. } while (0)
  419.  
  420. #define BCH_END_OPERATOR_RELOCATION        END_OPERATOR_RELOCATION
  421.  
  422. #define BCH_EXTRACT_OPERATOR_LINKAGE_ADDRESS(var, p_addr) do        \
  423. {                                    \
  424.   SCHEME_OBJECT * _p_addr, * _v_addr;                    \
  425.                                     \
  426.   _p_addr = ((SCHEME_OBJECT *) (((long) (p_addr)) + 3));        \
  427.   _v_addr = ((SCHEME_OBJECT *)                        \
  428.          (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));        \
  429.                                     \
  430.   BCH_EXTRACT_ADDRESS_FROM_DISPLACEMENT (var, _v_addr, _p_addr);    \
  431. } while (0)
  432.  
  433. #define BCH_STORE_OPERATOR_LINKAGE_ADDRESS(e_addr, p_addr) do        \
  434. {                                    \
  435.   SCHEME_OBJECT * _p_addr, * _v_addr;                    \
  436.                                     \
  437.   _p_addr = ((SCHEME_OBJECT *) (((long) (p_addr)) + 3));        \
  438.   _v_addr = ((SCHEME_OBJECT *)                        \
  439.          (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));        \
  440.                                     \
  441.   BCH_STORE_DISPLACEMENT_FROM_ADDRESS (e_addr, _v_addr, _p_addr);    \
  442. } while (0)
  443.  
  444. #define TRAMPOLINE_ENTRY_SIZE            3
  445. #define TRAMPOLINE_BLOCK_TO_ENTRY        3 /* MNV to MOV instr. */
  446.  
  447. #define STORE_TRAMPOLINE_ENTRY(entry_address, index) do            \
  448. {                                    \
  449.   unsigned char *PC = ((unsigned char *) (entry_address));        \
  450.                                     \
  451.   *PC++ = 0xb0;            /* MOV    AL,byte */            \
  452.   *PC++ = (index);        /* byte value */            \
  453.   *PC++ = 0xff;            /* CALL */                \
  454.   *PC++ = 0x96;            /* /2 disp32(ESI) */            \
  455.   (* ((unsigned long *) PC)) = ESI_TRAMPOLINE_TO_INTERFACE_OFFSET;    \
  456. } while (0)
  457.  
  458. #define TRAMPOLINE_ENTRY_POINT(tramp_block)                \
  459.   (((SCHEME_OBJECT *) (tramp_block)) + TRAMPOLINE_BLOCK_TO_ENTRY)
  460.  
  461. #define TRAMPOLINE_STORAGE(tramp_entry)                    \
  462.   ((((SCHEME_OBJECT *) (tramp_entry)) - TRAMPOLINE_BLOCK_TO_ENTRY) +    \
  463.    (2 + TRAMPOLINE_ENTRY_SIZE)) 
  464.  
  465. /* These must aggree with cmpaux-i386.m4!
  466.    The register block is actually allocated there.
  467.  */
  468.  
  469. #define COMPILER_REGBLOCK_N_FIXED        16
  470.  
  471. #define COMPILER_REGBLOCK_N_HOOKS        80
  472.  
  473.     /* A hook is the address (offset) of an assembly-language routine. */
  474.  
  475. #define COMPILER_HOOK_SIZE            1
  476.  
  477. #define COMPILER_REGBLOCK_EXTRA_SIZE                    \
  478.   (COMPILER_REGBLOCK_N_HOOKS * COMPILER_HOOK_SIZE)
  479.  
  480. #define REGBLOCK_ALLOCATED_BY_INTERFACE
  481.  
  482. #define ESI_TRAMPOLINE_TO_INTERFACE_OFFSET                \
  483.   ((COMPILER_REGBLOCK_N_FIXED + (2 * COMPILER_HOOK_SIZE)) *        \
  484.    (sizeof (SCHEME_OBJECT)))
  485.  
  486. #ifdef IN_CMPINT_C
  487.  
  488. #ifdef _MACH_UNIX
  489. #  include <mach.h>
  490. #  define VM_PROT_SCHEME (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
  491. #endif /* _MACH_UNIX */
  492.  
  493. long i386_pc_displacement_relocation = 0;
  494.  
  495. #define ASM_RESET_HOOK i386_reset_hook
  496.  
  497. /* This assumes that the layout in memory of a far pointer has the
  498.    segment index as the most significant half word.
  499.  */
  500.  
  501. #define SETUP_REGISTER(hook) do                        \
  502. {                                    \
  503.   extern void hook ();                            \
  504.                                     \
  505.   (* ((unsigned long *) (esi_value + offset))) =            \
  506.     ((unsigned long) hook);                        \
  507.   offset += (COMPILER_HOOK_SIZE * (sizeof (SCHEME_OBJECT)));        \
  508. } while (0)
  509.  
  510. void
  511. DEFUN_VOID (i386_reset_hook)
  512. {
  513.   extern int interface_initialize ();
  514.   int offset = (COMPILER_REGBLOCK_N_FIXED * (sizeof (SCHEME_OBJECT)));
  515.   unsigned char * esi_value = ((unsigned char *) (&Registers[0]));
  516.   int fp_support_present = (i386_interface_initialize ());
  517.  
  518.   /* These must match machines/i386/lapgen.scm */
  519.  
  520.   SETUP_REGISTER (asm_scheme_to_interface);         /* 0 */
  521.   SETUP_REGISTER (asm_scheme_to_interface_call);    /* 1 */
  522.  
  523.   if (offset != ESI_TRAMPOLINE_TO_INTERFACE_OFFSET)
  524.   {
  525.     fprintf (stderr,
  526.          "\ni386_reset_hook: ESI_TRAMPOLINE_TO_INTERFACE_OFFSET\n");
  527.     Microcode_Termination (TERM_EXIT);
  528.   }
  529.   SETUP_REGISTER (asm_trampoline_to_interface);        /* 2 */
  530.  
  531.   SETUP_REGISTER (asm_interrupt_procedure);        /* 3 */
  532.   SETUP_REGISTER (asm_interrupt_continuation);        /* 4 */
  533.   SETUP_REGISTER (asm_interrupt_closure);        /* 5 */
  534.   SETUP_REGISTER (asm_interrupt_dlink);            /* 6 */
  535.  
  536.   SETUP_REGISTER (asm_primitive_apply);            /* 7 */
  537.   SETUP_REGISTER (asm_primitive_lexpr_apply);        /* 8 */
  538.   SETUP_REGISTER (asm_assignment_trap);            /* 9 */
  539.   SETUP_REGISTER (asm_reference_trap);            /* 10 */
  540.   SETUP_REGISTER (asm_safe_reference_trap);        /* 11 */
  541.   SETUP_REGISTER (asm_link);                /* 12 */
  542.   SETUP_REGISTER (asm_error);                /* 13 */
  543.   SETUP_REGISTER (asm_primitive_error);            /* 14 */
  544.   SETUP_REGISTER (asm_short_primitive_apply);        /* 15 */
  545.  
  546.   /* This is a hack to make all the hooks be addressable
  547.      with byte offsets (instead of longword offsets).
  548.      The register block extends to negative offsets as well,
  549.      so all the following hooks are accessed with negative
  550.      offsets, and all fit in a byte.
  551.    */
  552.  
  553.   offset    = -128;
  554.  
  555.   if (fp_support_present != 0)
  556.   {
  557.     SETUP_REGISTER (asm_generic_add);            /* -32 */
  558.     SETUP_REGISTER (asm_generic_subtract);        /* -31 */
  559.     SETUP_REGISTER (asm_generic_multiply);        /* -30 */
  560.     SETUP_REGISTER (asm_generic_divide);        /* -29 */
  561.     SETUP_REGISTER (asm_generic_equal);            /* -28 */
  562.     SETUP_REGISTER (asm_generic_less);            /* -27 */
  563.     SETUP_REGISTER (asm_generic_greater);        /* -26 */
  564.     SETUP_REGISTER (asm_generic_increment);        /* -25 */
  565.     SETUP_REGISTER (asm_generic_decrement);        /* -24 */
  566.     SETUP_REGISTER (asm_generic_zero);            /* -23 */
  567.     SETUP_REGISTER (asm_generic_positive);        /* -22 */
  568.     SETUP_REGISTER (asm_generic_negative);        /* -21 */
  569.     SETUP_REGISTER (asm_generic_quotient);        /* -20 */
  570.     SETUP_REGISTER (asm_generic_remainder);        /* -19 */
  571.     SETUP_REGISTER (asm_generic_modulo);        /* -18 */
  572.   }
  573.   else
  574.   {
  575.     SETUP_REGISTER (asm_nofp_add);            /* -32 */
  576.     SETUP_REGISTER (asm_nofp_subtract);            /* -31 */
  577.     SETUP_REGISTER (asm_nofp_multiply);            /* -30 */
  578.     SETUP_REGISTER (asm_nofp_divide);            /* -29 */
  579.     SETUP_REGISTER (asm_nofp_equal);            /* -28 */
  580.     SETUP_REGISTER (asm_nofp_less);            /* -27 */
  581.     SETUP_REGISTER (asm_nofp_greater);            /* -26 */
  582.     SETUP_REGISTER (asm_nofp_increment);        /* -25 */
  583.     SETUP_REGISTER (asm_nofp_decrement);        /* -24 */
  584.     SETUP_REGISTER (asm_nofp_zero);            /* -23 */
  585.     SETUP_REGISTER (asm_nofp_positive);            /* -22 */
  586.     SETUP_REGISTER (asm_nofp_negative);            /* -21 */
  587.     SETUP_REGISTER (asm_nofp_quotient);            /* -20 */
  588.     SETUP_REGISTER (asm_nofp_remainder);        /* -19 */
  589.     SETUP_REGISTER (asm_nofp_modulo);            /* -18 */
  590.   }
  591.  
  592.   SETUP_REGISTER (asm_sc_apply);            /* -17 */
  593.   SETUP_REGISTER (asm_sc_apply_size_1);            /* -16 */
  594.   SETUP_REGISTER (asm_sc_apply_size_2);            /* -15 */
  595.   SETUP_REGISTER (asm_sc_apply_size_3);            /* -14 */
  596.   SETUP_REGISTER (asm_sc_apply_size_4);            /* -13 */
  597.   SETUP_REGISTER (asm_sc_apply_size_5);            /* -12 */
  598.   SETUP_REGISTER (asm_sc_apply_size_6);            /* -11 */
  599.   SETUP_REGISTER (asm_sc_apply_size_7);            /* -10 */
  600.   SETUP_REGISTER (asm_sc_apply_size_8);            /* -9 */
  601.  
  602. #ifdef _MACH_UNIX
  603.   {
  604.     vm_address_t addr;
  605.     vm_size_t size;
  606.     vm_prot_t prot;
  607.     vm_prot_t max_prot;
  608.     vm_inherit_t inheritance;
  609.     boolean_t shared;
  610.     port_t object;
  611.     vm_offset_t offset;
  612.  
  613.     addr = ((vm_address_t) Heap);
  614.     if ((vm_region ((task_self ()), &addr, &size, &prot, &max_prot,
  615.             &inheritance, &shared, &object, &offset))
  616.     != KERN_SUCCESS)
  617.     {
  618.       fprintf (stderr, "compiler_reset: vm_region() failed.\n");
  619.       Microcode_Termination (TERM_EXIT);
  620.       /*NOTREACHED*/
  621.     }
  622.     if ((prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
  623.     {
  624.       if ((max_prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
  625.       {
  626.     fprintf (stderr,
  627.          "compiler_reset: inadequate protection for Heap.\n");
  628.     fprintf (stderr, "maximum = 0x%lx; desired = 0x%lx\n",
  629.          ((unsigned long) (max_prot & VM_PROT_SCHEME)),
  630.          ((unsigned long) VM_PROT_SCHEME));
  631.     Microcode_Termination (TERM_EXIT);
  632.     /*NOTREACHED*/
  633.       }
  634.       if ((vm_protect ((task_self ()), ((vm_address_t) Heap),
  635.                (((char *) Constant_Top) - ((char *) Heap)),
  636.                0, VM_PROT_SCHEME))
  637.       != KERN_SUCCESS)
  638.       {
  639.     fprintf (stderr,
  640.          "compiler_reset: unable to change protection for Heap.\n");
  641.     fprintf (stderr, "actual = 0x%lx; desired = 0x%lx\n",
  642.          ((unsigned long) (prot & VM_PROT_SCHEME)),
  643.          ((unsigned long) VM_PROT_SCHEME));
  644.     Microcode_Termination (TERM_EXIT);
  645.     /*NOTREACHED*/
  646.       }
  647.     }
  648.   }
  649. #endif /* _MACH_UNIX */
  650.  
  651.   return;
  652. }
  653.  
  654. #endif /* IN_CMPINT_C */
  655.  
  656. /* Derived parameters and macros.
  657.    These macros expect the above definitions to be meaningful.
  658.    If they are not, the macros below may have to be changed as well.
  659.  */
  660.  
  661. #define COMPILED_ENTRY_OFFSET_WORD(entry)                               \
  662.   (((format_word *) (entry))[-1])
  663. #define COMPILED_ENTRY_FORMAT_WORD(entry)                               \
  664.   (((format_word *) (entry))[-2])
  665.  
  666. /* The next one assumes 2's complement integers....*/
  667. #define CLEAR_LOW_BIT(word)                     ((word) & ((unsigned long) -2))
  668. #define OFFSET_WORD_CONTINUATION_P(word)        (((word) & 1) != 0)
  669.  
  670. #if (PC_ZERO_BITS == 0)
  671. /* Instructions aligned on byte boundaries */
  672. #define BYTE_OFFSET_TO_OFFSET_WORD(offset)      ((offset) << 1)
  673. #define OFFSET_WORD_TO_BYTE_OFFSET(offset_word)                         \
  674.   ((CLEAR_LOW_BIT(offset_word)) >> 1)
  675. #endif
  676.  
  677. #if (PC_ZERO_BITS == 1)
  678. /* Instructions aligned on word (16 bit) boundaries */
  679. #define BYTE_OFFSET_TO_OFFSET_WORD(offset)      (offset)
  680. #define OFFSET_WORD_TO_BYTE_OFFSET(offset_word)                         \
  681.   (CLEAR_LOW_BIT(offset_word))
  682. #endif
  683.  
  684. #if (PC_ZERO_BITS >= 2)
  685. /* Should be OK for =2, but bets are off for >2 because of problems
  686.    mentioned earlier!
  687. */
  688. #define SHIFT_AMOUNT                            (PC_ZERO_BITS - 1)
  689. #define BYTE_OFFSET_TO_OFFSET_WORD(offset)      ((offset) >> (SHIFT_AMOUNT))
  690. #define OFFSET_WORD_TO_BYTE_OFFSET(offset_word)                         \
  691.   ((CLEAR_LOW_BIT(offset_word)) << (SHIFT_AMOUNT))
  692. #endif
  693.  
  694. #define MAKE_OFFSET_WORD(entry, block, continue)                        \
  695.   ((BYTE_OFFSET_TO_OFFSET_WORD(((char *) (entry)) -                     \
  696.                                ((char *) (block)))) |                   \
  697.    ((continue) ? 1 : 0))
  698.  
  699. #if (EXECUTE_CACHE_ENTRY_SIZE == 2)
  700. #define EXECUTE_CACHE_COUNT_TO_ENTRIES(count)                           \
  701.   ((count) >> 1)
  702. #define EXECUTE_CACHE_ENTRIES_TO_COUNT(entries)                \
  703.   ((entries) << 1)
  704. #endif
  705.  
  706. #if (EXECUTE_CACHE_ENTRY_SIZE == 4)
  707. #define EXECUTE_CACHE_COUNT_TO_ENTRIES(count)                           \
  708.   ((count) >> 2)
  709. #define EXECUTE_CACHE_ENTRIES_TO_COUNT(entries)                \
  710.   ((entries) << 2)
  711. #endif
  712.  
  713. #if (!defined(EXECUTE_CACHE_COUNT_TO_ENTRIES))
  714. #define EXECUTE_CACHE_COUNT_TO_ENTRIES(count)                           \
  715.   ((count) / EXECUTE_CACHE_ENTRY_SIZE)
  716. #define EXECUTE_CACHE_ENTRIES_TO_COUNT(entries)                \
  717.   ((entries) * EXECUTE_CACHE_ENTRY_SIZE)
  718. #endif
  719.  
  720. /* The first entry in a cc block is preceeded by 2 headers (block and nmv),
  721.    a format word and a gc offset word.   See the early part of the
  722.    TRAMPOLINE picture, above.
  723.  */
  724.  
  725. #define CC_BLOCK_FIRST_ENTRY_OFFSET                                     \
  726.   (2 * ((sizeof(SCHEME_OBJECT)) + (sizeof(format_word))))
  727.  
  728. /* Format words */
  729.  
  730. #define FORMAT_BYTE_EXPR                0xFF
  731. #define FORMAT_BYTE_COMPLR              0xFE
  732. #define FORMAT_BYTE_CMPINT              0xFD
  733. #define FORMAT_BYTE_DLINK               0xFC
  734. #define FORMAT_BYTE_RETURN              0xFB
  735.  
  736. #define FORMAT_WORD_EXPR        (MAKE_FORMAT_WORD(0xFF, FORMAT_BYTE_EXPR))
  737. #define FORMAT_WORD_CMPINT      (MAKE_FORMAT_WORD(0xFF, FORMAT_BYTE_CMPINT))
  738. #define FORMAT_WORD_RETURN      (MAKE_FORMAT_WORD(0xFF, FORMAT_BYTE_RETURN))
  739.  
  740. /* This assumes that a format word is at least 16 bits,
  741.    and the low order field is always 8 bits.
  742.  */
  743.  
  744. #define MAKE_FORMAT_WORD(field1, field2)                                \
  745.   (((field1) << 8) | ((field2) & 0xff))
  746.  
  747. #define SIGN_EXTEND_FIELD(field, size)                                  \
  748.   (((field) & ((1 << (size)) - 1)) |                                    \
  749.    ((((field) & (1 << ((size) - 1))) == 0) ? 0 :                        \
  750.     ((-1) << (size))))
  751.  
  752. #define FORMAT_WORD_LOW_BYTE(word)                                      \
  753.   (SIGN_EXTEND_FIELD((((unsigned long) (word)) & 0xff), 8))
  754.  
  755. #define FORMAT_WORD_HIGH_BYTE(word)                    \
  756.   (SIGN_EXTEND_FIELD((((unsigned long) (word)) >> 8),            \
  757.              (((sizeof (format_word)) * CHAR_BIT) - 8)))
  758.  
  759. #define COMPILED_ENTRY_FORMAT_HIGH(addr)                                \
  760.   (FORMAT_WORD_HIGH_BYTE(COMPILED_ENTRY_FORMAT_WORD(addr)))
  761.  
  762. #define COMPILED_ENTRY_FORMAT_LOW(addr)                                 \
  763.   (FORMAT_WORD_LOW_BYTE(COMPILED_ENTRY_FORMAT_WORD(addr)))
  764.  
  765. #define FORMAT_BYTE_FRAMEMAX            0x7f
  766.  
  767. #define COMPILED_ENTRY_MAXIMUM_ARITY    COMPILED_ENTRY_FORMAT_LOW
  768. #define COMPILED_ENTRY_MINIMUM_ARITY    COMPILED_ENTRY_FORMAT_HIGH
  769.  
  770. #endif /* CMPINT2_H_INCLUDED */
  771.